/**
 * 
 */
package com.dfhc.pub.service;

import java.sql.Date;
import java.util.List;

import org.quickbundle.project.RmProjectHelper;
import org.quickbundle.project.common.vo.RmCommonVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.dfhc.ISystemConstant;
import com.dfhc.PjException;
import com.dfhc.base.impulsesender.vo.ImpulseSenderVo;
import com.dfhc.client.vo.ResponseNextValueVo;
import com.dfhc.util.ConvertHelper;
import com.dfhc.util.DateUtil;
import com.dfhc.util.StringHelper;

/**
 * @author 龙色波 序列值服务
 */
@Service
// 默认将类中的所有public函数纳入事务管理
public class SequenceService {
	//域表名
	private final String DOMAIN_TABLE_NAME="BASE_DOMAIN";
	//发号器表名
	private final String TABLE_NAME = "BASE_IMPULSE_SENDER";
	// 日期字段名
	private final String FIELD_DATE = "update_date";
	// 当期值字段名
	private final String FIELD_CURRENT_VALUE = "current_value";
	// 序列值长度
	private final String FIELD_SEQUENCE_LEN = "sequence_len";
	// 当期格式化后序列值
	private final String FIELD_CURRENT_FMT_VALUE = "current_fmt_value";
	// 序列化格式规则
	private final String FIELD_SEQUENCE_RULE = "sequence_rule";
	// 序列名称
	private final String FIELD_SEQUENCE = "sequence_name";
	// 周期类型
	private final String FIELD_CYCLE_TYPE = "cycle_type";

	// 域名ID
	private final String FIELD_DOMAIN_ID="domain_id";
	// 域名 
	private final String FIELD_DOMAIN_NAME="name";
	/**
	 * 获取下一批序列值
	 * 
	 * @param size 序列个数
	 * @param domainName 域名称
	 * @param sequenceName
	 *            序列名称
	 * @param args
	 *            参数列表
	 * @return
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW) 
	public String[] doGetNextSequenceValue(int size,String domainName,String sequenceName, Object... args) {
		return getNextSequenceValue(size,domainName, sequenceName, args);
	}
	/**
	 * 获取下一批序列值
	 * 
	 * @param size 序列个数
	 * @param domainName 域名称
	 * @param sequenceName
	 *            序列名称
	 * @param args
	 *            参数列表
	 * @return
	 */
	private String[] getNextSequenceValue(int size,String domainName, String sequenceName,
			Object... args) {
        ResponseNextValueVo responseVo = doGetNewNextSequenceValue(size, domainName, sequenceName, args);
        if(ISystemConstant.Result.SUCCESS.code().equals(responseVo.getErrorCode())){
			String retVals[] = new String[size];
			int curVal = responseVo.getMaxValue();
			int startVal = responseVo.getMinValue();
			// 格式当期值为字符串
			Integer valLen;
			valLen = responseVo.getSenderVo().getSequenceLen();
			
			// 获取序列格式化规则
			String sequenRule = responseVo.getSenderVo().getSequenceRule();
			String curValFmt = "%0" + ConvertHelper.toString(valLen) + "d";
			String fmtCurVal;
			for(int i=startVal;i<=curVal;i++){			
				String strCurVal = String.format(curValFmt, i);		
				// 将规则中的%value替换为strCurVal,然后再格式化
				sequenRule = StringHelper.replaceAll(responseVo.getSenderVo().getSequenceRule(), ISystemConstant.FMT_SEQ_VALUE,strCurVal).toString();
				fmtCurVal = String.format(sequenRule, args);
				retVals[i-startVal]=fmtCurVal;
			}
			return retVals;
        }else{
        	throw new PjException(responseVo.getErrorMsg());
        }
	}
	/**
	 * 获取下一批序列值
	 * 
	 * @param size 序列个数
	 * @param domainName 域名称
	 * @param sequenceName
	 *            序列名称
	 * @param args
	 *            参数列表
	 * @return
	 */
	public ResponseNextValueVo doGetNewNextSequenceValue(int size,String domainName, String sequenceName,
			Object... args) {
		ResponseNextValueVo responseVo = new ResponseNextValueVo();
		responseVo.setDomainName(domainName);
		responseVo.setSequenceName(sequenceName);
		responseVo.setNum(size);
		// 序列记录加锁
		String sql;
		//判断size的值
		if(size<=0){
			//throw new PjException("无效获取序列个数:"+size);
			responseVo.setErrorCode(ISystemConstant.Result.INVALID_SEQUENCE_NUM.code());
			responseVo.setErrorMsg(String.format(ISystemConstant.Result.INVALID_SEQUENCE_NUM.msg(), size));
			return responseVo;
		}
	
		sql = "select * from " + TABLE_NAME + " where " + FIELD_SEQUENCE + "='"
				+ sequenceName + "' AND "+  FIELD_DOMAIN_ID+ "=(SELECT ID FROM "+DOMAIN_TABLE_NAME+" where  "+FIELD_DOMAIN_NAME+"='"+domainName+"') for update";
		List<RmCommonVo> vos = RmProjectHelper.getCommonServiceInstance()
				.doQuery(sql);
		if (vos == null || vos.size() == 0) {
			//throw new PjException("域名称:"+domainName+",序列名称:" + sequenceName + "不存在!");
			responseVo.setErrorCode(ISystemConstant.Result.NOTEXISTS_DOMAINNAME_SEQUENCENAME.code());
			responseVo.setErrorMsg(String.format(ISystemConstant.Result.NOTEXISTS_DOMAINNAME_SEQUENCENAME.msg(), domainName,sequenceName));
			return responseVo;
		}
		RmCommonVo vo = vos.get(0);

		java.sql.Date sqlDate;
		sqlDate = (java.sql.Date) vo.get(FIELD_DATE);
		java.sql.Date dbDate;
		dbDate = getDBTimestamp();
		if(sqlDate==null){
			sqlDate = dbDate;
		}
		// 取出周期类型
		String cycleDateType = ISystemConstant.CYCLE_TYPE_NO;
		if (vo.get(FIELD_CYCLE_TYPE) != null) {
			cycleDateType = vo.getString(FIELD_CYCLE_TYPE);
		}
		Integer curVal;
		String fmtCurVal="";
		Integer currentValue;
		// 判断是否有周期
		if (!ISystemConstant.CYCLE_TYPE_NO.equals(cycleDateType)) {
			// 按年
			if (ISystemConstant.CYCLE_TYPE_YEAR.equals(cycleDateType)) {
				Integer curryear = DateUtil.getYear(dbDate);
				Integer dbYear = 0;
				try {
					dbYear = ConvertHelper.toInteger(DateUtil.getDateStr(
							sqlDate, "yyyy"));
				} catch (Exception e) {
//					throw new PjException(e.getMessage());
					responseVo.setErrorCode(ISystemConstant.Result.CONVERT_FAIL.code());
					responseVo.setErrorMsg(String.format(ISystemConstant.Result.CONVERT_FAIL.msg(),e.getMessage()));
					return responseVo;
					
				}
				if (!dbYear.equals(curryear)) {
					// 年份不同,需要从size开始
					curVal = size;
				} else {
					currentValue = (Integer) vo.get(FIELD_CURRENT_VALUE);
					// 当期值加size
					if(currentValue!=null){
						curVal = currentValue.intValue();
					}else{
						curVal = 0;
					}
					if (curVal == null) {
						curVal = 0;
					}
					curVal = curVal + size;
				}
				// 按月
			} else if (ISystemConstant.CYCLE_TYPE_MONTH.equals(cycleDateType)) {
				//改成年和月联合比较 ，以免出现年份不同，月份相同的bug  modify at 2014-12-12
				String currMonth = DateUtil.getDateStr(dbDate,"yyyyMM");
				String dbMonth = "";
				dbMonth = DateUtil.getDateStr(sqlDate, "yyyyMM");
				
				if (!dbMonth.equals(currMonth)) {
					// 月份不同,需要从size开始
					curVal = size;
				} else {
					// 当期值加size
					currentValue = (Integer) vo.get(FIELD_CURRENT_VALUE);
					// 当期值加size
					if(currentValue!=null){
						curVal = currentValue.intValue();
					}else{
						curVal = 0;
					}
					if (curVal == null) {
						curVal = 0;
					}
					curVal = curVal + size;
				}
				// 按天
			} else if (ISystemConstant.CYCLE_TYPE_DAY.equals(cycleDateType)) {
				//改成年，月和日联合比较 ，以免出现年份不同，月份不同，但日相同的bug modify at 2014-12-12
				String currDay = DateUtil.getDateStr(dbDate,"yyyyMMdd");
				String dbDay = "";
				dbDay = DateUtil.getDateStr(sqlDate, "yyyyMMdd");				
				if (!dbDay.equals(currDay)) {
					// 天不同,需要从size开始
					curVal = size;
				} else {
					// 当期值加size
					currentValue = (Integer) vo.get(FIELD_CURRENT_VALUE);
					if(currentValue!=null){
						curVal = currentValue.intValue();
					}else{
						curVal = 0;
					}
					if (curVal == null) {
						curVal = 0;
					}
					curVal = curVal + size;
				}
				// 其他按无周期处理
			} else {
				// 当期值加size
				currentValue = (Integer) vo.get(FIELD_CURRENT_VALUE);
				// 当期值加size
				if(currentValue!=null){
					curVal = currentValue.intValue();
				}else{
					curVal = 0;
				}
				if (curVal == null) {
					curVal = 0;
				}
				curVal = curVal + size;
			}
		} else {
			// 当期值加size
			currentValue = (Integer) vo.get(FIELD_CURRENT_VALUE);
			// 当期值加size
			if(currentValue!=null){
				curVal = currentValue.intValue();
			}else{
				curVal = 0;
			}
			if (curVal == null) {
				curVal = 0;
			}
			curVal = curVal + size;
		}
		//String retVals[] = new String[size];
		int startVal = curVal-size+1;
		responseVo.setMinValue(startVal);
		responseVo.setMaxValue(curVal);
		// 格式当期值为字符串
		Integer sequenceLen;
		sequenceLen = (Integer)vo.get(FIELD_SEQUENCE_LEN);
		Integer valLen = sequenceLen; 
		if (valLen == null) {
//			throw new PjException("序列名称:" + sequenceName + "的长度尚未定义!");
			responseVo.setErrorCode(ISystemConstant.Result.SEQUENCE_LEN_NOT_DEFINE.code());
			responseVo.setErrorMsg(String.format(ISystemConstant.Result.SEQUENCE_LEN_NOT_DEFINE.msg(),sequenceName));
			return responseVo;
		}
		// 获取序列格式化规则
		String sequenRule = vo.getString(FIELD_SEQUENCE_RULE);
		if (StringHelper.isEmpty(sequenRule)) {
//			throw new PjException("序列名称:" + sequenceName + "的规则尚未定义!");
			responseVo.setErrorCode(ISystemConstant.Result.SEQUENCE_RULE_NOT_DEFINE.code());
			responseVo.setErrorMsg(String.format(ISystemConstant.Result.SEQUENCE_RULE_NOT_DEFINE.msg(),sequenceName));
			return responseVo;
		}
		String curValFmt = "%0" + ConvertHelper.toString(valLen) + "d";
		
//		for(int i=startVal;i<=curVal;i++){			
//			String strCurVal = String.format(curValFmt, i);		
//			// 将规则中的%value替换为strCurVal,然后再格式化
//			sequenRule = StringHelper.replaceAll(vo.getString(FIELD_SEQUENCE_RULE), FMT_SEQ_VALUE,strCurVal).toString();
//			fmtCurVal = String.format(sequenRule, args);
//			retVals[i-startVal]=fmtCurVal;
//		}
		String strCurVal = String.format(curValFmt, curVal);		
		// 将规则中的%value替换为strCurVal,然后再格式化
		sequenRule = StringHelper.replaceAll(vo.getString(FIELD_SEQUENCE_RULE), ISystemConstant.FMT_SEQ_VALUE,strCurVal).toString();
		fmtCurVal = String.format(sequenRule, args);
		// 更新数据库
		sql = "update " + TABLE_NAME + " set " + FIELD_CURRENT_VALUE + "="
				+ curVal + "," + FIELD_CURRENT_FMT_VALUE + "='" + fmtCurVal
				+ "'," + FIELD_DATE + "=sysDate()";

		sql = sql + " where " + FIELD_SEQUENCE + "='" + sequenceName + "' AND "+  FIELD_DOMAIN_ID+ "=(SELECT ID FROM "+DOMAIN_TABLE_NAME+" where  "+FIELD_DOMAIN_NAME+"='"+domainName+"')";
		int rowNum = RmProjectHelper.getCommonServiceInstance().doUpdate(sql);
		if (rowNum < 1) {
//			throw new PjException("产生序列名称:" + sequenceName
//					+ "失败!原因为更新记录数小于1!");
			responseVo.setErrorCode(ISystemConstant.Result.UPDATE_SEQUENCE_FAIL.code());
			responseVo.setErrorMsg(String.format(ISystemConstant.Result.UPDATE_SEQUENCE_FAIL.msg(),sequenceName));
			return responseVo;
		}		
		//设置成功标志
		responseVo.setErrorCode(ISystemConstant.Result.SUCCESS.code());
		responseVo.setErrorMsg(ISystemConstant.Result.SUCCESS.msg());
		ImpulseSenderVo senderVo = responseVo.getSenderVo();
		senderVo.setCycleType(vo.getString(FIELD_CYCLE_TYPE));
		senderVo.setDomainId(vo.getString(FIELD_DOMAIN_ID));
		senderVo.setDomainName(vo.getString(FIELD_DOMAIN_NAME));
		senderVo.setSequenceLen(sequenceLen);
		senderVo.setSequenceRule(vo.getString(FIELD_SEQUENCE_RULE));
		responseVo.setSenderVo(senderVo);
		return responseVo;
	}	
	/**
	 * 获取下一个序列值
	 * @param domainName 域名称
	 * @param sequenceName
	 *            序列名称
	 * @param args
	 *            参数列表
	 * @return
	 */
	@Transactional(propagation=Propagation.REQUIRES_NEW) 
	public String doGetNextSequenceValue(String domainName,String sequenceName, Object... args) {
		String seqValues[];
		seqValues = getNextSequenceValue(1,domainName, sequenceName, args);
		if(seqValues!=null && seqValues.length>0){
			return seqValues[0];
		}else{
			return null;
		}
	}
	
	/**
	 * 获取数据库时间戳
	 * @return
	 */
	private Date getDBTimestamp() {
		RmCommonVo vo = RmProjectHelper.getCommonServiceInstance().doQueryForObject("select sysdate() as sysdate ");
		java.sql.Timestamp t = (java.sql.Timestamp) vo.get("sysdate");
		java.sql.Date retDate;
		retDate = DateUtil.toSqlDate(DateUtil.timestamp2date(t));
		return retDate;
	}
    /**
     * 生成随机数
     * 
     */ 
    
    public long doRandomNum(long max ,long min){
    
    	return Math.round(Math.random()*(max-min))+min;
    	
    }	
    
  
}
